#region Includes

using System;
using System.Collections.Generic;
using System.Text;

using System.Configuration;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Collections.Specialized;

using ca.metaobjects.csogateway.Configuration;
using ca.metaobjects.csogateway.Reflection;

#endregion

namespace ca.metaobjects.csogateway
{
    /// <summary>
    /// JSObjectLoader
    /// </summary>
    public class JSObjectLoader
    {

        #region Static Class Fields

		private static readonly Dictionary<String, LibraryTypeDefinition> htNameToCsoLibTypeDef = null;
		
		private static readonly Dictionary<Type, CsoGeneratedTypeDefinition> htTypeToCsoGenTypeDef = null;
		private static readonly Dictionary<String, CsoGeneratedTypeDefinition> htNameToCsoGenTypeDef = null;

		private static CsoGeneratedTypesConfigSection csoConfigSection = null;

		private static Assembly csoGatewayAssembly;
		private static string[] resourceNames = null;

		private static Library csoLibraryTypes;

		//private static String msAjaxFileName = null;
		//private static String msAjaxFileString = null;

        #endregion

        #region Static Constructor

        static JSObjectLoader()
        {
            try
            {
				csoConfigSection = (CsoGeneratedTypesConfigSection)ConfigurationManager.GetSection("CsoGeneratedTypesConfigSection");

				htTypeToCsoGenTypeDef = new Dictionary<Type, CsoGeneratedTypeDefinition>();
				htNameToCsoGenTypeDef = new Dictionary<string, CsoGeneratedTypeDefinition>();

				csoGatewayAssembly = Assembly.GetExecutingAssembly();
				resourceNames = csoGatewayAssembly.GetManifestResourceNames();

				//loadMsAjaxFile();
				loadCsoLibraryTypes();
				loadCsoGeneratedTypes();

            }
            catch (Exception ex)
            {
                throw new CSOException("Error while creating javascript types for CsoGateway. See inner exception for more details.", ex);
            }
        }

        #endregion

		#region Loading methods
		/*
		private static void loadMsAjaxFile()
		{
			//load ms ajax library

			Assembly a = Assembly.GetExecutingAssembly();
			string completeMsAjaxFileName = null;
			string[] resourceNames = a.GetManifestResourceNames();

			for (int i = 0; (i < resourceNames.Length) && (completeMsAjaxFileName == null); ++i)
			{
				if (resourceNames[i].EndsWith(msAjaxFileName))
					completeMsAjaxFileName = resourceNames[i];
			}

			StreamReader sr = new StreamReader(a.GetManifestResourceStream(completeMsAjaxFileName));

			msAjaxFileString = sr.ReadToEnd();
		}
		*/

		private static void loadCsoLibraryTypes()
		{
			XmlSerializer ser = new XmlSerializer(typeof(Library));

			csoLibraryTypes = ser.Deserialize(getResourceStream("CsoLibraryTypes.xml")) as Library;
			csoLibraryTypes.initializeServerTypeClientTypeMapping();

			LibraryTypeDefinition typeDefinition;
			ClientSideTypeInformation typeInfo;
			LibraryTypeDefinition dependencyDef;

			foreach(ClientSideTypeInformation info in csoLibraryTypes.Types)
			{
				typeDefinition = new LibraryTypeDefinition();
				typeDefinition.JsNamespace = info.jsNamespace;
				typeDefinition.JsTypeName = info.typeName;
				typeDefinition.InFileName = info.inFile;

				foreach (DependencyInformation dependencyInfo in info.Dependencies)
				{
					typeInfo = csoLibraryTypes.getClientSideTypeInformationFromId(dependencyInfo.id);
					dependencyDef = htNameToCsoLibTypeDef[String.Format("{0}.{1}", typeInfo.jsNamespace, typeInfo.typeName)];

					if (dependencyDef == null)
						throw new CSOException("Error in creating type definition object for CSO Gateway library type " + typeDefinition.JsFullTypeName +
							". The type definition " + String.Format("{0}.{1}", typeInfo.jsNamespace, typeInfo.typeName) +
							" should have been created already since it is a dependency.");

					typeDefinition.addDependency(dependencyDef);
				}
			}

		}

		private static void loadCsoGeneratedTypes()
		{
			CsoGeneratedTypeDefinition typeDefinition;

			foreach (CsoGeneratedTypesConfigSectionElement csoConfigElement in csoConfigSection.Classes)
			{
				Type type = Type.GetType(csoConfigElement.Type);

				typeDefinition = new CsoGeneratedTypeDefinition();
				typeDefinition.ServerSideType = type;
				typeDefinition.JsNamespace = GetJsNamespace(type);
				typeDefinition.JsTypeName = GetJsTypeName(type);
				typeDefinition.JsTypeSourceCode = GenerateJSClassToString(type);

				htTypeToCsoGenTypeDef.Add(type, typeDefinition);
				htNameToCsoGenTypeDef.Add(csoConfigElement.Name, typeDefinition);
			}

			//load all the enums
			foreach (CsoGeneratedTypesConfigSectionElement csoConfigElement in csoConfigSection.Enums)
			{
				Type type = Type.GetType(csoConfigElement.Type);

				typeDefinition = new CsoGeneratedTypeDefinition();
				typeDefinition.ServerSideType = type;
				typeDefinition.JsNamespace = GetJsNamespace(type);
				typeDefinition.JsTypeName = GetJsTypeName(type);
				typeDefinition.JsTypeSourceCode = GenerateJSEnumToString(type);

				htTypeToCsoGenTypeDef.Add(type, typeDefinition);
				htNameToCsoGenTypeDef.Add(csoConfigElement.Name, typeDefinition);
			}
		}

		private static Stream getResourceStream(string endOfName)
		{
			string fileName = null;
			for (int i = 0; (i < resourceNames.Length) && (fileName == null); ++i)
			{
				if (resourceNames[i].EndsWith(endOfName))
					fileName = resourceNames[i];
			}

			if (fileName == null)
				throw new CSOException("Manifest of CsoGateway assembly does not contain a resource with a name ending with " + String.Format("{0}",endOfName));

			return csoGatewayAssembly.GetManifestResourceStream(fileName);
		}

		

		#endregion

		#region Public Properties
		public static Library ClientSideTypeLibrary
		{
			get
			{
				return csoLibraryTypes;
			}
		}
		#endregion

		#region Public Methods

		/// <summary>
        /// Gets the type definition.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static CsoGeneratedTypeDefinition GetTypeDefinition(Type type)
        {
            return htTypeToCsoGenTypeDef[type];
        }

        /// <summary>
        /// Gets the CSO script.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static string GetCSOscript(string name)
        {
			if (htNameToCsoGenTypeDef[name] == null)
				throw new CSOException("No javascript type definition found for " + name);

            return ((CsoGeneratedTypeDefinition)htNameToCsoGenTypeDef[name]).JsTypeSourceCode;
        }

		/*
		public static string GetMsAjaxFileString()
		{
			return msAjaxFileString;
		}
		*/

        /// <summary>
        /// Determines whether [is cso declared] [the specified type].
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>
        /// 	<c>true</c> if [is cso declared] [the specified type]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsCsoDeclared(Type type)
        {
			return (htTypeToCsoGenTypeDef.ContainsKey(type) && htTypeToCsoGenTypeDef[type] != null);
        }

        /// <summary>
        /// Generates the JS enum to file.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="type">The type.</param>
        public static void GenerateJSEnumToFile(string path, Type type)
        {
            string location = string.IsNullOrEmpty(path) ? type.Name : Path.Combine(path, type.Name);

            TextWriter tw = new StreamWriter(location + ".js");
            using (tw)
            {
                // look for class decorated with CSOAttribute
                foreach (object attribute in type.GetCustomAttributes(typeof(CSOAttribute), false))
                {
                    CSOAttribute classAttribute = attribute as CSOAttribute;
                    if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.JsNamespace))
                    {
                        // generate JS enum
                        tw.WriteLine("//JScript file");
                        tw.WriteLine("Type.registerNamespace(\"" + classAttribute.JsNamespace + "\");");
                        tw.WriteLine();
                        tw.WriteLine("// **********");
                        tw.WriteLine("// " + type.Name + " entity");
                        tw.WriteLine("// **********");
                        tw.WriteLine(string.Format("{0}.{1} = function(){{}};", classAttribute.JsNamespace, type.Name));

                        tw.WriteLine(string.Format("{0}.{1}.prototype = ", classAttribute.JsNamespace, type.Name));
                        tw.WriteLine("{");
                        tw.WriteLine(GenerateJSEnumParams(type));
                        tw.WriteLine("}");
                        tw.WriteLine();

                        // register JS enum
                        tw.WriteLine(string.Format("{0}.{1}.registerEnum('{0}.{1}');", classAttribute.JsNamespace, type.Name));
                    }
                }
            }
        }

        /// <summary>
        /// Writes the JS file.
        /// </summary>
        /// <param name="member">The member.</param>
        public static void GenerateJSToFile(string path, MemberInfo member)
        {
            string location = string.IsNullOrEmpty(path) ? member.Name : Path.Combine(path, member.Name);

            TextWriter tw = new StreamWriter(location + ".js");
            using (tw)
            {
                // look for class with CSOAttribute declared
                foreach (object attribute in member.GetCustomAttributes(typeof(CSOAttribute), false))
                {
                    CSOAttribute classAttribute = attribute as CSOAttribute;
                    if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.JsNamespace))
                    {
                        // get all the properties for class
                        CommaDelimitedStringCollection parameters = GetCSOProperties((Type)member);

						// get hash sources
						CommaDelimitedStringCollection hashSources = GetCSOHashSources((Type)member);
						

                        //see if parent is configured CSO configured
                        CommaDelimitedStringCollection parentParams = new CommaDelimitedStringCollection();
                        parentParams = GetCSOProperties(((Type)member).BaseType);

                        string combinedParams = ((parentParams.Count > 0) ? parentParams.ToString() + "," + parameters.ToString() : parameters.ToString());

                        // generate JS class
                        tw.WriteLine("  Type.registerNamespace(\"" + classAttribute.JsNamespace + "\");");
                        tw.WriteLine();
                        tw.WriteLine("// **********");
                        tw.WriteLine("// " + member.Name + " entity");
                        tw.WriteLine("// **********");
                        tw.WriteLine(string.Format("{0}.{1} = function {0}${1}({2})", classAttribute.JsNamespace, member.Name, combinedParams));
                        tw.WriteLine("{");

                        if (parentParams.Count > 0)
                        {
                            tw.WriteLine();
                            tw.WriteLine(string.Format("    {0}.{1}.initializeBase(this, [{2}]);", classAttribute.JsNamespace, member.Name, parentParams.ToString()));
                            tw.WriteLine();
                        }

                        foreach (string param in parameters)
                        {
                            tw.WriteLine(string.Format("  this._{0} = {0};", param));
                        }
                        tw.WriteLine("}");

                        // generate properties
                        tw.WriteLine();
                        foreach (string param in parameters)
                        {
                            tw.WriteLine("// " + param + " property");
                            tw.WriteLine(string.Format("{0}.{1}.prototype.get_{2} = function {0}${1}$get_{2}()", classAttribute.JsNamespace, member.Name, CapitalizeString(param)));
                            tw.WriteLine("{");
                            tw.WriteLine("  return this._" + param + ";");
                            tw.WriteLine("}");
                            tw.WriteLine(string.Format("{0}.{1}.prototype.set_{2} = function {0}${1}$set_{2}(value)", classAttribute.JsNamespace, member.Name, CapitalizeString(param)));
                            tw.WriteLine("{");
                            tw.WriteLine("  this._" + param + " = value;");
                            tw.WriteLine("}");
                            tw.WriteLine();
                        }

						if (hashSources.Count > 0)
						{
							tw.WriteLine();
							tw.WriteLine("//Hash sources");
							tw.WriteLine(string.Format("{0}.{1}.prototype.getCsoHashSource = function {0}${1}$getCsoHashSource()", classAttribute.JsNamespace, member.Name));
							tw.WriteLine("{");
							tw.WriteLine("  return new Array(");
							for(int i=0; i<hashSources.Count; i++)
							{
								tw.WriteLine("this._" + hashSources[i] + ((i==(hashSources.Count-1)) ? String.Empty : ","));
							}
							tw.WriteLine("  );");
							tw.WriteLine("}");
						}

                        // register JS class
                        tw.WriteLine(string.Format("{0}.{1}.registerClass('{0}.{1}', {2}, Sys.IDisposable);", classAttribute.JsNamespace, member.Name, GetParentCSOConfigured(((Type)member).BaseType)));
                    }
                }
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Capitalizes the string.
        /// </summary>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        private static string CapitalizeString(string param)
        {
            return param.Substring(0, 1).ToUpper() + param.Substring(1);
        }

        /// <summary>
        /// Decapitalizes the string.
        /// </summary>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        private static string DecapitalizeString(string param)
        {
            return param.Substring(0, 1).ToLower() + param.Substring(1);
        }

		/// <summary>
		/// Gets the Hash source properties.
		/// </summary>
		/// <param name="className">Name of the class.</param>
		/// <returns></returns>
		private static CommaDelimitedStringCollection GetCSOHashSources(Type type)
		{
			CommaDelimitedStringCollection sources = new CommaDelimitedStringCollection();

			// get the properties of the class decorated with HashSource attribute
			foreach (MemberInfo prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
			{
				// Add all properties marked as a hash source
				bool addProp = false;
				foreach (object atr in prop.GetCustomAttributes(typeof(CSOHashSourceAttribute), false))
				{
					CSOHashSourceAttribute paramAttribute = atr as CSOHashSourceAttribute;
					if (paramAttribute != null)
					{
						addProp = true;
					}
				}
				if (addProp)
				{
					//Make sure the property is compatable with the CSOObjectCreator
					MethodInfo[] info = ((PropertyInfo)prop).GetAccessors();
					if (!IsPropertyCsoConfigured(info[0]))
					{
						throw new CSOException(string.Format("Cannot use property of with return type '{0}' as a hash source. This type is not currently support by the CSOObjectCreator.", info[0].ReturnParameter.ParameterType.FullName));
					}

					sources.Add(DecapitalizeString(prop.Name));
				}
			}
			return sources;
		}

        /// <summary>
        /// Gets the CSO properties.
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <returns></returns>
        private static CommaDelimitedStringCollection GetCSOProperties(Type type)
        {
            CommaDelimitedStringCollection parameters = new CommaDelimitedStringCollection();

            // get all the properties of the class
            foreach (MemberInfo prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
            {
                // add all the properties unless marked to exclude
                bool addProp = true;
                foreach (object atr in prop.GetCustomAttributes(typeof(CSOExcludeAttribute), false))
                {
                    CSOExcludeAttribute paramAttribute = atr as CSOExcludeAttribute;
                    if (paramAttribute != null)
                    {
                        addProp = false;
                    }
                }
                if (addProp)
                {
                    //make sure the property is compatable with the CSOObjectCreator
                    MethodInfo[] info = ((PropertyInfo)prop).GetAccessors();
                    if (!IsPropertyCsoConfigured(info[0]))
                    {
                        throw new CSOException(string.Format("Unable to generate client-side JS for property with return type '{0}'. This type is not currently support by the CSOObjectCreator.", info[0].ReturnParameter.ParameterType.FullName));
                    }

                    parameters.Add(DecapitalizeString(prop.Name));
                }
            }
            return parameters;
        }

        /// <summary>
        /// Determines whether property is CSO compatable. This is to comply with the CSOObjectCreator
        /// </summary>
        /// <param name="info">The info.</param>
        /// <returns>
        /// 	<c>true</c> if [is property cso configured] [the specified info]; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsPropertyCsoConfigured(MethodInfo info)
        {
            bool isCsoConfigured = (
				(info.ReturnParameter.ParameterType == typeof(String)) ||
				(info.ReturnParameter.ParameterType == typeof(Int16)) ||
				(info.ReturnParameter.ParameterType == typeof(Int32)) ||
				(info.ReturnParameter.ParameterType == typeof(Int64)) ||
				(info.ReturnParameter.ParameterType == typeof(Byte)) ||
				(info.ReturnParameter.ParameterType == typeof(Single)) ||
				(info.ReturnParameter.ParameterType == typeof(Double)) ||
				(info.ReturnParameter.ParameterType == typeof(Boolean)) ||
				(info.ReturnParameter.ParameterType == typeof(Decimal)) ||
				(info.ReturnParameter.ParameterType == typeof(DateTime)) ||
				(info.ReturnParameter.ParameterType.IsEnum &&
					info.ReturnParameter.ParameterType.GetCustomAttributes(typeof(CSOAttribute), false).Length > 0) ||
				(info.ReturnParameter.ParameterType.GetInterface("ICollection", true) != null) ||
				(info.ReturnParameter.ParameterType == typeof(StringDictionary))

				);

            return isCsoConfigured;
        }

        /// <summary>
        /// Gets the js namespace.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        private static string GetJsNamespace(MemberInfo member)
        {
            object[] csoAttributes = member.GetCustomAttributes(typeof(CSOAttribute), false);

            if (csoAttributes.Length != 1)
                throw new CSOException(string.Format("Unable to locate JSnamespace for {0}", member.Name));

            return ((CSOAttribute)csoAttributes[0]).JsNamespace;
        }

        /// <summary>
        /// Gets the name of the js type.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        private static string GetJsTypeName(MemberInfo member)
        {
            return member.Name;
        }

        /// <summary>
        /// Generates the JS enum to string.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        private static string GenerateJSEnumToString(Type type)
        {
            StringBuilder sb = new StringBuilder();

            // look for class decorated with CSOAttribute
            foreach (object attribute in type.GetCustomAttributes(typeof(CSOAttribute), false))
            {
                CSOAttribute classAttribute = attribute as CSOAttribute;
                if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.JsNamespace))
                {
                    // generate JS enum
                    sb.AppendLine("Type.registerNamespace(\"" + classAttribute.JsNamespace + "\");");
                    sb.AppendLine();
                    sb.AppendLine("// **********");
                    sb.AppendLine("// " + type.Name + " entity");
                    sb.AppendLine("// **********");
                    sb.AppendLine(string.Format("{0}.{1} = function(){{}};", classAttribute.JsNamespace, type.Name));

                    sb.AppendLine(string.Format("{0}.{1}.prototype = ", classAttribute.JsNamespace, type.Name));
                    sb.AppendLine("{");
                    sb.AppendLine(GenerateJSEnumParams(type));
                    sb.AppendLine("}");
                    sb.AppendLine();

                    // register JS enum
                    sb.AppendLine(string.Format("{0}.{1}.registerEnum('{0}.{1}');", classAttribute.JsNamespace, type.Name));
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// Generates the JS to string.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        private static string GenerateJSEnumParams(Type type)
        {
            StringBuilder sb = new StringBuilder();
            List<string> names = new List<string>();
            List<string> values = new List<string>();

            foreach (string name in Enum.GetNames(type))
            {
                names.Add(name);
            }
            foreach (int val in Enum.GetValues(type))
            {
                values.Add(val.ToString());
            }
            for (int i = 0; i < names.Count; i++)
            {
                sb.Append(names[i] + ":" + values[i]);
                if (i < names.Count - 1)
                {
                    sb.AppendLine(",");
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// Generates the JS to string.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        private static string GenerateJSClassToString(MemberInfo member)
        {
            StringBuilder sb = new StringBuilder();

            // look for class decorated with CSOAttribute
            foreach (object attribute in member.GetCustomAttributes(typeof(CSOAttribute), false))
            {
                CSOAttribute classAttribute = attribute as CSOAttribute;
                if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.JsNamespace))
                {
                    // get all the properties for class
                    CommaDelimitedStringCollection parameters = GetCSOProperties((Type)member);

                    //see if parent is configured CSO configured
                    CommaDelimitedStringCollection parentParams = new CommaDelimitedStringCollection();
                    parentParams = GetCSOProperties(((Type)member).BaseType);

					// get hash sources
					CommaDelimitedStringCollection hashSources = GetCSOHashSources((Type)member);

					string combinedParams = ((parentParams.Count > 0) ? parentParams.ToString() + "," + parameters.ToString() : parameters.ToString());

                    // generate JS class
                    sb.AppendLine("//JScript file");
                    sb.AppendLine("  Type.registerNamespace(\"" + classAttribute.JsNamespace + "\");");
                    sb.AppendLine();
                    sb.AppendLine("// **********");
                    sb.AppendLine("// " + member.Name + " entity");
                    sb.AppendLine("// **********");
                    sb.AppendLine(string.Format("{0}.{1} = function {0}${1}({2})", classAttribute.JsNamespace, member.Name, combinedParams));
                    sb.AppendLine("{");

                    // initialize base js class
                    if (parentParams.Count > 0)
                    {
                        sb.AppendLine();
                        sb.AppendLine(string.Format("   {0}.{1}.initializeBase(this, [{2}]);", classAttribute.JsNamespace, member.Name, parentParams.ToString()));
                        sb.AppendLine();
                    }

                    foreach (string param in parameters)
                    {
                        sb.AppendLine(string.Format("  this._{0} = {0};", param));
                    }
                    sb.AppendLine("}");

                    // generate properties
                    sb.AppendLine();
                    foreach (string param in parameters)
                    {
                        sb.AppendLine("// " + param + " property");
                        sb.AppendLine(string.Format("{0}.{1}.prototype.get_{2} = function {0}${1}$get_{2}()", classAttribute.JsNamespace, member.Name, CapitalizeString(param)));
                        sb.AppendLine("{");
                        sb.AppendLine("  return this._" + param + ";");
                        sb.AppendLine("}");
                        sb.AppendLine(string.Format("{0}.{1}.prototype.set_{2} = function {0}${1}$set_{2}(value)", classAttribute.JsNamespace, member.Name, CapitalizeString(param)));
                        sb.AppendLine("{");
                        sb.AppendLine("  this._" + param + " = value;");
                        sb.AppendLine("}");
                        sb.AppendLine();
                    }

					// generate hash source property
					if (hashSources.Count > 0)
					{
						sb.AppendLine("//Hash sources");
						sb.AppendLine(string.Format("{0}.{1}.prototype.getCsoHashSource = function {0}${1}$getCsoHashSource()", classAttribute.JsNamespace, member.Name));
						sb.AppendLine("{");
						sb.AppendLine("  return new Array(");
						for (int i = 0; i < hashSources.Count; i++)
						{
							sb.AppendLine("    this._" + hashSources[i] + ((i == (hashSources.Count - 1)) ? String.Empty : ","));
						}
						sb.AppendLine("  );");
						sb.AppendLine("}");
					}

                    // register JS class                                       
                    sb.AppendLine(string.Format(
						"{0}.{1}.registerClass('{0}.{1}', {2}{3});",
						classAttribute.JsNamespace,
						member.Name,
						GetParentCSOConfigured(((Type)member).BaseType),
						GetCSOInterfaces(true, hashSources.Count>0)
						));
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// Determines whether [is parent CSO configured] [the specified type].
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        private static string GetParentCSOConfigured(Type type)
        {
            string parentNamespace = string.Empty;

            // look for class decorated with CSOAttribute
            foreach (object attribute in type.GetCustomAttributes(typeof(CSOAttribute), false))
            {
                CSOAttribute classAttribute = attribute as CSOAttribute;
                if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.JsNamespace))
                {
                    parentNamespace = classAttribute.JsNamespace + "." + type.Name;
                }
            }

            //didn't find anything? set to CSOGenerated then
            if (string.IsNullOrEmpty(parentNamespace))
            {
				parentNamespace = "CsoGateway.CsoGenerated";
            }

            return parentNamespace;
        }

		private static string GetCSOInterfaces(bool implementsDisposable, bool implementsHashProvider)
		{
			string interfaces = String.Empty;

			if(implementsDisposable)
			{
				interfaces += (", Sys.IDisposable");
			}
			if(implementsHashProvider)
			{
				interfaces += (", CsoGateway.Collections.ICsoHashProvider");
			}

			return interfaces;
		}

		#endregion
	}
}